home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / stunnel-4.04 / _src / src / options.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-01  |  39.6 KB  |  1,401 lines

  1. /*
  2.  *   stunnel       Universal SSL tunnel
  3.  *   Copyright (c) 1998-2002 Michal Trojnara <Michal.Trojnara@mirt.net>
  4.  *                 All Rights Reserved
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 2 of the License, or
  9.  *   (at your option) any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   In addition, as a special exception, Michal Trojnara gives
  21.  *   permission to link the code of this program with the OpenSSL
  22.  *   library (or with modified versions of OpenSSL that use the same
  23.  *   license as OpenSSL), and distribute linked combinations including
  24.  *   the two.  You must obey the GNU General Public License in all
  25.  *   respects for all of the code used other than OpenSSL.  If you modify
  26.  *   this file, you may extend this exception to your version of the
  27.  *   file, but you are not obligated to do so.  If you do not wish to
  28.  *   do so, delete this exception statement from your version.
  29.  */
  30.  
  31. #include "common.h"
  32. #include "prototypes.h"
  33.  
  34. static int host2nums(char *, u32 **);
  35. static int parse_debug_level(char *);
  36. static int parse_ssl_option(char *);
  37. static int print_socket_options(void);
  38. static void print_option(char *, int, OPT_UNION *);
  39. static int parse_socket_option(char *);
  40. static char *section_validate(LOCAL_OPTIONS *);
  41. static char *stralloc(char *);
  42. #ifndef USE_WIN32
  43. static char **argalloc(char *);
  44. #endif
  45.  
  46. GLOBAL_OPTIONS options;
  47. LOCAL_OPTIONS local_options;
  48.  
  49. typedef enum {
  50.     CMD_INIT, /* initialize */
  51.     CMD_EXEC,
  52.     CMD_DEFAULT,
  53.     CMD_HELP
  54. } CMD;
  55.  
  56. static char *option_not_found="Specified option name is not valid here";
  57.  
  58. static char *global_options(CMD cmd, char *opt, char *arg) {
  59.  
  60.     if(cmd==CMD_DEFAULT || cmd==CMD_HELP) {
  61.         log_raw("Global options");
  62.     }
  63.  
  64.     /* CApath */
  65.     switch(cmd) {
  66.     case CMD_INIT:
  67. #if 0
  68.         options.ca_dir=(char *)X509_get_default_cert_dir();
  69. #endif
  70.         options.ca_dir=NULL;
  71.         break;
  72.     case CMD_EXEC:
  73.         if(strcasecmp(opt, "CApath"))
  74.             break;
  75.         if(arg[0]) /* not empty */
  76.             options.ca_dir=stralloc(arg);
  77.         else
  78.             options.ca_dir=NULL;
  79.         return NULL; /* OK */
  80.     case CMD_DEFAULT:
  81. #if 0
  82.         log_raw("%-15s = %s", "CApath",
  83.             options.ca_dir ? options.ca_dir : "(none)");
  84. #endif
  85.         break;
  86.     case CMD_HELP:
  87.         log_raw("%-15s = CA certificate directory for 'verify' option",
  88.             "CApath");
  89.         break;
  90.     }
  91.  
  92.     /* CAfile */
  93.     switch(cmd) {
  94.     case CMD_INIT:
  95. #if 0
  96.         options.ca_file=(char *)X509_get_default_certfile();
  97. #endif
  98.         options.ca_file=NULL;
  99.         break;
  100.     case CMD_EXEC:
  101.         if(strcasecmp(opt, "CAfile"))
  102.             break;
  103.         if(arg[0]) /* not empty */
  104.             options.ca_file=stralloc(arg);
  105.         else
  106.             options.ca_file=NULL;
  107.         return NULL; /* OK */
  108.     case CMD_DEFAULT:
  109. #if 0
  110.         log_raw("%-15s = %s", "CAfile",
  111.             options.ca_file ? options.ca_file : "(none)");
  112. #endif
  113.         break;
  114.     case CMD_HELP:
  115.         log_raw("%-15s = CA certificate file for 'verify' option",
  116.             "CAfile");
  117.         break;
  118.     }
  119.  
  120.     /* cert */
  121.     switch(cmd) {
  122.     case CMD_INIT:
  123. #ifdef CONFDIR
  124.         options.cert=CONFDIR "/stunnel.pem";
  125. #else
  126.         options.cert="stunnel.pem";
  127. #endif
  128.         break;
  129.     case CMD_EXEC:
  130.         if(strcasecmp(opt, "cert"))
  131.             break;
  132.         options.cert=stralloc(arg);
  133.         options.option.cert=1;
  134.         return NULL; /* OK */
  135.     case CMD_DEFAULT:
  136.         log_raw("%-15s = %s", "cert", options.cert);
  137.         break;
  138.     case CMD_HELP:
  139.         log_raw("%-15s = certificate chain", "cert");
  140.         break;
  141.     }
  142.  
  143.     /* chroot */
  144. #ifdef HAVE_CHROOT
  145.     switch(cmd) {
  146.     case CMD_INIT:
  147.         options.chroot_dir=NULL;
  148.         break;
  149.     case CMD_EXEC:
  150.         if(strcasecmp(opt, "chroot"))
  151.             break;
  152.         options.chroot_dir=stralloc(arg);
  153.         return NULL; /* OK */
  154.     case CMD_DEFAULT:
  155.         break;
  156.     case CMD_HELP:
  157.         log_raw("%-15s = directory to chroot stunnel process", "chroot");
  158.         break;
  159.     }
  160. #endif /* HAVE_CHROOT */
  161.  
  162.     /* ciphers */
  163.     switch(cmd) {
  164.     case CMD_INIT:
  165.         options.cipher_list=SSL_DEFAULT_CIPHER_LIST;
  166.         break;
  167.     case CMD_EXEC:
  168.         if(strcasecmp(opt, "ciphers"))
  169.             break;
  170.         options.cipher_list=stralloc(arg);
  171.         return NULL; /* OK */
  172.     case CMD_DEFAULT:
  173.         log_raw("%-15s = %s", "ciphers", SSL_DEFAULT_CIPHER_LIST);
  174.         break;
  175.     case CMD_HELP:
  176.         log_raw("%-15s = list of permitted SSL ciphers", "ciphers");
  177.         break;
  178.     }
  179.  
  180.     /* client */
  181.     switch(cmd) {
  182.     case CMD_INIT:
  183.         options.option.client=0;
  184.         break;
  185.     case CMD_EXEC:
  186.         if(strcasecmp(opt, "client"))
  187.             break;
  188.         if(!strcasecmp(arg, "yes"))
  189.             options.option.client=1;
  190.         else if(!strcasecmp(arg, "no"))
  191.             options.option.client=0;
  192.         else
  193.             return "argument should be either 'yes' or 'no'";
  194.         return NULL; /* OK */
  195.     case CMD_DEFAULT:
  196.         break;
  197.     case CMD_HELP:
  198.         log_raw("%-15s = yes|no client mode (remote service uses SSL)",
  199.             "client");
  200.         break;
  201.     }
  202.  
  203.     /* debug */
  204.     switch(cmd) {
  205.     case CMD_INIT:
  206.         options.debug_level=5;
  207. #if !defined (USE_WIN32) && !defined (__vms)
  208.         options.facility=LOG_DAEMON;
  209. #endif
  210.         break;
  211.     case CMD_EXEC:
  212.         if(strcasecmp(opt, "debug"))
  213.             break;
  214.         if(!parse_debug_level(arg))
  215.             return "Illegal debug argument";
  216.         return NULL; /* OK */
  217.     case CMD_DEFAULT:
  218.         log_raw("%-15s = %d", "debug", options.debug_level);
  219.         break;
  220.     case CMD_HELP:
  221.         log_raw("%-15s = [facility].level (e.g. daemon.info)", "debug");
  222.         break;
  223.     }
  224.  
  225.     /* EGD is only supported when compiled with OpenSSL 0.9.5a or later */
  226. #if SSLEAY_VERSION_NUMBER >= 0x0090581fL
  227.     switch(cmd) {
  228.     case CMD_INIT:
  229.         options.egd_sock=NULL;
  230.         break;
  231.     case CMD_EXEC:
  232.         if(strcasecmp(opt, "EGD"))
  233.             break;
  234.         options.egd_sock=stralloc(arg);
  235.         return NULL; /* OK */
  236.     case CMD_DEFAULT:
  237. #ifdef EGD_SOCKET
  238.         log_raw("%-15s = %s", "EGD", EGD_SOCKET);
  239. #endif
  240.         break;
  241.     case CMD_HELP:
  242.         log_raw("%-15s = path to Entropy Gathering Daemon socket", "EGD");
  243.         break;
  244.     }
  245. #endif /* OpenSSL 0.9.5a */
  246.  
  247.     /* foreground */
  248. #ifndef USE_WIN32
  249.     switch(cmd) {
  250.     case CMD_INIT:
  251.         options.option.syslog=0;
  252.         options.option.foreground=0;
  253.         break;
  254.     case CMD_EXEC:
  255.         if(strcasecmp(opt, "foreground"))
  256.             break;
  257.         if(!strcasecmp(arg, "yes"))
  258.             options.option.foreground=1;
  259.         else if(!strcasecmp(arg, "no"))
  260.             options.option.foreground=0;
  261.         else
  262.             return "argument should be either 'yes' or 'no'";
  263.         return NULL; /* OK */
  264.     case CMD_DEFAULT:
  265.         break;
  266.     case CMD_HELP:
  267.         log_raw("%-15s = yes|no foreground mode (don't fork, log to stderr)",
  268.             "foreground");
  269.         break;
  270.     }
  271. #endif
  272.  
  273.     /* key */
  274.     switch(cmd) {
  275.     case CMD_INIT:
  276.         options.key=NULL;
  277.         break;
  278.     case CMD_EXEC:
  279.         if(strcasecmp(opt, "key"))
  280.             break;
  281.         options.key=stralloc(arg);
  282.         return NULL; /* OK */
  283.     case CMD_DEFAULT:
  284.         log_raw("%-15s = %s", "key", options.cert); /* set in stunnel.c */
  285.         break;
  286.     case CMD_HELP:
  287.         log_raw("%-15s = certificate private key", "key");
  288.         break;
  289.     }
  290.  
  291.     /* options */
  292.     switch(cmd) {
  293.     case CMD_INIT:
  294.         options.ssl_options=0;
  295.         break;
  296.     case CMD_EXEC:
  297.         if(strcasecmp(opt, "options"))
  298.             break;
  299.         if(!parse_ssl_option(arg))
  300.             return "Illegal SSL option";
  301.         return NULL; /* OK */
  302.     case CMD_DEFAULT:
  303.         break;
  304.     case CMD_HELP:
  305.         log_raw("%-15s = SSL option", "options");
  306.         log_raw("%18sset an SSL option", "");
  307.         break;
  308.     }
  309.  
  310.     /* output */
  311.     switch(cmd) {
  312.     case CMD_INIT:
  313.         options.output_file=NULL;
  314.         break;
  315.     case CMD_EXEC:
  316.         if(strcasecmp(opt, "output"))
  317.             break;
  318.         options.output_file=stralloc(arg);
  319.         return NULL; /* OK */
  320.     case CMD_DEFAULT:
  321.         break;
  322.     case CMD_HELP:
  323.         log_raw("%-15s = file to append log messages", "output");
  324.         break;
  325.     }
  326.  
  327.     /* pid */
  328. #ifndef USE_WIN32
  329.     switch(cmd) {
  330.     case CMD_INIT:
  331.         options.pidfile=PIDFILE;
  332.         break;
  333.     case CMD_EXEC:
  334.         if(strcasecmp(opt, "pid"))
  335.             break;
  336.         if(arg[0]) /* is argument not empty? */
  337.             options.pidfile=stralloc(arg);
  338.         else
  339.             options.pidfile=NULL; /* empty -> do not create a pid file */
  340.         return NULL; /* OK */
  341.     case CMD_DEFAULT:
  342.         log_raw("%-15s = %s", "pid", PIDFILE);
  343.         break;
  344.     case CMD_HELP:
  345.         log_raw("%-15s = pid file (empty to disable creating)", "pid");
  346.         break;
  347.     }
  348. #endif
  349.  
  350.     /* RNDbytes */
  351.     switch(cmd) {
  352.     case CMD_INIT:
  353.         options.random_bytes=RANDOM_BYTES;
  354.         break;
  355.     case CMD_EXEC:
  356.         if(strcasecmp(opt, "RNDbytes"))
  357.             break;
  358.         options.random_bytes=atoi(arg);
  359.         return NULL; /* OK */
  360.     case CMD_DEFAULT:
  361.         log_raw("%-15s = %d", "RNDbytes", RANDOM_BYTES);
  362.         break;
  363.     case CMD_HELP:
  364.         log_raw("%-15s = bytes to read from random seed files", "RNDbytes");
  365.         break;
  366.     }
  367.  
  368.     /* RNDfile */
  369.     switch(cmd) {
  370.     case CMD_INIT:
  371.         options.rand_file=NULL;
  372.         break;
  373.     case CMD_EXEC:
  374.         if(strcasecmp(opt, "RNDfile"))
  375.             break;
  376.         options.rand_file=stralloc(arg);
  377.         return NULL; /* OK */
  378.     case CMD_DEFAULT:
  379. #ifdef RANDOM_FILE
  380.         log_raw("%-15s = %s", "RNDfile", RANDOM_FILE);
  381. #endif
  382.         break;
  383.     case CMD_HELP:
  384.         log_raw("%-15s = path to file with random seed data", "RNDfile");
  385.         break;
  386.     }
  387.  
  388.     /* RNDoverwrite */
  389.     switch(cmd) {
  390.     case CMD_INIT:
  391.         options.option.rand_write=1;
  392.         break;
  393.     case CMD_EXEC:
  394.         if(strcasecmp(opt, "RNDoverwrite"))
  395.             break;
  396.         if(!strcasecmp(arg, "yes"))
  397.             options.option.rand_write=1;
  398.         else if(!strcasecmp(arg, "no"))
  399.             options.option.rand_write=0;
  400.         else
  401.             return "argument should be either 'yes' or 'no'";
  402.         return NULL; /* OK */
  403.     case CMD_DEFAULT:
  404.         log_raw("%-15s = yes", "RNDoverwrite");
  405.         break;
  406.     case CMD_HELP:
  407.         log_raw("%-15s = yes|no overwrite seed datafiles with new random data",
  408.             "RNDoverwrite");
  409.         break;
  410.     }
  411.  
  412.     /* service */
  413.     switch(cmd) {
  414.     case CMD_INIT:
  415.         local_options.servname=stralloc("stunnel");
  416. #ifdef USE_WIN32
  417.         options.win32_service="stunnel";
  418.         options.win32_name="stunnel " VERSION " on Win32";
  419. #endif
  420.         break;
  421.     case CMD_EXEC:
  422.         if(strcasecmp(opt, "service"))
  423.             break;
  424.         local_options.servname=stralloc(arg);
  425. #ifdef USE_WIN32
  426.         options.win32_service=stralloc(arg);
  427.         {
  428.             char tmpstr[STRLEN];
  429.  
  430.             safecopy(tmpstr, "stunnel " VERSION " on Win32 (");
  431.             safeconcat(tmpstr, arg);
  432.             safeconcat(tmpstr, ")");
  433.             options.win32_name=stralloc(tmpstr);
  434.         }
  435. #endif
  436.         return NULL; /* OK */
  437.     case CMD_DEFAULT:
  438. #ifdef USE_WIN32
  439.         log_raw("%-15s = %s", "service", options.win32_service);
  440. #endif
  441.         break;
  442.     case CMD_HELP:
  443.         log_raw("%-15s = service name", "service");
  444.         break;
  445.     }
  446.  
  447.     /* session */
  448.     switch(cmd) {
  449.     case CMD_INIT:
  450.         options.session_timeout=300;
  451.         break;
  452.     case CMD_EXEC:
  453.         if(strcasecmp(opt, "session"))
  454.             break;
  455.         if(atoi(arg)>0)
  456.             options.session_timeout=atoi(arg);
  457.         else
  458.             return "Illegal session timeout";
  459.         return NULL; /* OK */
  460.     case CMD_DEFAULT:
  461.         log_raw("%-15s = %ld seconds", "session", options.session_timeout);
  462.         break;
  463.     case CMD_HELP:
  464.         log_raw("%-15s = session cache timeout (in seconds)", "session");
  465.         break;
  466.     }
  467.  
  468. #ifndef USE_WIN32
  469.     /* setgid */
  470.     switch(cmd) {
  471.     case CMD_INIT:
  472.         options.setgid_group=NULL;
  473.         break;
  474.     case CMD_EXEC:
  475.         if(strcasecmp(opt, "setgid"))
  476.             break;
  477.         options.setgid_group=stralloc(arg);
  478.         return NULL; /* OK */
  479.     case CMD_DEFAULT:
  480.         break;
  481.     case CMD_HELP:
  482.         log_raw("%-15s = groupname for setgid()", "setgid");
  483.         break;
  484.     }
  485. #endif
  486.  
  487. #ifndef USE_WIN32
  488.     /* setuid */
  489.     switch(cmd) {
  490.     case CMD_INIT:
  491.         options.setuid_user=NULL;
  492.         break;
  493.     case CMD_EXEC:
  494.         if(strcasecmp(opt, "setuid"))
  495.             break;
  496.         options.setuid_user=stralloc(arg);
  497.         return NULL; /* OK */
  498.     case CMD_DEFAULT:
  499.         break;
  500.     case CMD_HELP:
  501.         log_raw("%-15s = username for setuid()", "setuid");
  502.         break;
  503.     }
  504. #endif
  505.  
  506.     /* socket */
  507.     switch(cmd) {
  508.     case CMD_INIT:
  509.         break;
  510.     case CMD_EXEC:
  511.         if(strcasecmp(opt, "socket"))
  512.             break;
  513.         if(!parse_socket_option(arg))
  514.             return "Illegal socket option";
  515.         return NULL; /* OK */
  516.     case CMD_DEFAULT:
  517.         break;
  518.     case CMD_HELP:
  519.         log_raw("%-15s = a|l|r:option=value[:value]", "socket");
  520.         log_raw("%18sset an option on accept/local/remote socket", "");
  521.         break;
  522.     }
  523.  
  524.     /* verify */
  525.     switch(cmd) {
  526.     case CMD_INIT:
  527.         options.verify_level=-1;
  528.         options.verify_use_only_my=0;
  529.         break;
  530.     case CMD_EXEC:
  531.         if(strcasecmp(opt, "verify"))
  532.             break;
  533.         options.verify_level=SSL_VERIFY_NONE;
  534.         switch(atoi(arg)) {
  535.         case 3:
  536.             options.verify_use_only_my=1;
  537.         case 2:
  538.             options.verify_level|=SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  539.         case 1:
  540.             options.verify_level|=SSL_VERIFY_PEER;
  541.         case 0:
  542.             return NULL; /* OK */
  543.         default:
  544.             return "Bad verify level";
  545.         }
  546.     case CMD_DEFAULT:
  547.         log_raw("%-15s = none", "verify");
  548.         break;
  549.     case CMD_HELP:
  550.         log_raw("%-15s = level of peer certificate verification", "verify");
  551.         log_raw("%18slevel 1 - verify peer certificate if present", "");
  552.         log_raw("%18slevel 2 - require valid peer certificate always", "");
  553.         log_raw("%18slevel 3 - verify peer with locally installed certificate",
  554.         "");
  555.         break;
  556.     }
  557.  
  558.     if(cmd==CMD_EXEC)
  559.         return option_not_found;
  560.     return NULL; /* OK */
  561. }
  562.  
  563. static char *service_options(CMD cmd, LOCAL_OPTIONS *section,
  564.         char *opt, char *arg) {
  565.  
  566.     if(cmd==CMD_DEFAULT || cmd==CMD_HELP) {
  567.         log_raw(" ");
  568.         log_raw("Service-level options");
  569.     }
  570.  
  571.     /* accept */
  572.     switch(cmd) {
  573.     case CMD_INIT:
  574.         section->option.accept=0;
  575.         break;
  576.     case CMD_EXEC:
  577.         if(strcasecmp(opt, "accept"))
  578.             break;
  579.         section->option.accept=1;
  580.         if(!name2nums(arg, "0.0.0.0",
  581.                 §ion->localnames, §ion->localport))
  582.             exit(2);
  583.         return NULL; /* OK */
  584.     case CMD_DEFAULT:
  585.         break;
  586.     case CMD_HELP:
  587.         log_raw("%-15s = [host:]port accept connections on specified host:port",
  588.             "accept");
  589.         break;
  590.     }
  591.  
  592.     /* connect */
  593.     switch(cmd) {
  594.     case CMD_INIT:
  595.         section->option.remote=0;
  596.         section->remote_address=NULL;
  597.         section->remotenames=NULL;
  598.         section->remoteport=0;
  599.         break;
  600.     case CMD_EXEC:
  601.         if(strcasecmp(opt, "connect"))
  602.             break;
  603.         section->option.remote=1;
  604.         section->remote_address=stralloc(arg);
  605.         if(!section->option.delayed_lookup && !name2nums(arg, "127.0.0.1",
  606.                 §ion->remotenames, §ion->remoteport)) {
  607.             log_raw("Cannot resolve '%s' - delaying DNS lookup", arg);
  608.             section->option.delayed_lookup=1;
  609.         }
  610.         return NULL; /* OK */
  611.     case CMD_DEFAULT:
  612.         break;
  613.     case CMD_HELP:
  614.         log_raw("%-15s = [host:]port connect remote host:port",
  615.             "connect");
  616.         break;
  617.     }
  618.  
  619.     /* delay */
  620.     switch(cmd) {
  621.     case CMD_INIT:
  622.         section->option.delayed_lookup=0;
  623.         break;
  624.     case CMD_EXEC:
  625.         if(strcasecmp(opt, "delay"))
  626.             break;
  627.         if(!strcasecmp(arg, "yes"))
  628.             section->option.delayed_lookup=1;
  629.         else if(!strcasecmp(arg, "no"))
  630.             section->option.delayed_lookup=0;
  631.         else
  632.             return "argument should be either 'yes' or 'no'";
  633.         return NULL; /* OK */
  634.     case CMD_DEFAULT:
  635.         break;
  636.     case CMD_HELP:
  637.         log_raw("%-15s = yes|no delay DNS lookup for 'connect' option",
  638.             "delay");
  639.         break;
  640.     }
  641.  
  642.     /* exec */
  643. #ifndef USE_WIN32
  644.     switch(cmd) {
  645.     case CMD_INIT:
  646.         section->option.program=0;
  647.         section->execname=NULL;
  648.         break;
  649.     case CMD_EXEC:
  650.         if(strcasecmp(opt, "exec"))
  651.             break;
  652.         section->option.program=1;
  653.         section->execname=stralloc(arg);
  654.         return NULL; /* OK */
  655.     case CMD_DEFAULT:
  656.         break;
  657.     case CMD_HELP:
  658.         log_raw("%-15s = file execute local inetd-type program",
  659.             "exec");
  660.         break;
  661.     }
  662. #endif
  663.  
  664.     /* execargs */
  665. #ifndef USE_WIN32
  666.     switch(cmd) {
  667.     case CMD_INIT:
  668.         section->execargs=NULL;
  669.         break;
  670.     case CMD_EXEC:
  671.         if(strcasecmp(opt, "execargs"))
  672.             break;
  673.         section->execargs=argalloc(arg);
  674.         return NULL; /* OK */
  675.     case CMD_DEFAULT:
  676.         break;
  677.     case CMD_HELP:
  678.         log_raw("%-15s = arguments for 'exec' (including $0)",
  679.             "execargs");
  680.         break;
  681.     }
  682. #endif
  683.  
  684.     /* ident */
  685.     switch(cmd) {
  686.     case CMD_INIT:
  687.         section->username=NULL;
  688.         break;
  689.     case CMD_EXEC:
  690.         if(strcasecmp(opt, "ident"))
  691.             break;
  692.         section->username=stralloc(arg);
  693.         return NULL; /* OK */
  694.     case CMD_DEFAULT:
  695.         break;
  696.     case CMD_HELP:
  697.         log_raw("%-15s = username for IDENT (RFC 1413) checking", "ident");
  698.         break;
  699.     }
  700.  
  701.     /* local */
  702.     switch(cmd) {
  703.     case CMD_INIT:
  704.         section->local_ip=NULL;
  705.         break;
  706.     case CMD_EXEC:
  707.         if(strcasecmp(opt, "local"))
  708.             break;
  709.         if(!host2nums(arg, &(section->local_ip)))
  710.             exit(2);
  711.         return NULL; /* OK */
  712.     case CMD_DEFAULT:
  713.         break;
  714.     case CMD_HELP:
  715.         log_raw("%-15s = IP address to be used as source for remote"
  716.             " connections", "local");
  717.         break;
  718.     }
  719.  
  720.     /* protocol */
  721.     switch(cmd) {
  722.     case CMD_INIT:
  723.         section->protocol=NULL;
  724.         break;
  725.     case CMD_EXEC:
  726.         if(strcasecmp(opt, "protocol"))
  727.             break;
  728.         section->protocol=stralloc(arg);
  729.         return NULL; /* OK */
  730.     case CMD_DEFAULT:
  731.         break;
  732.     case CMD_HELP:
  733.         log_raw("%-15s = protocol to negotiate before SSL initialization",
  734.             "protocol");
  735.         log_raw("%18scurrently supported: smtp, pop3, nntp", "");
  736.         break;
  737.     }
  738.  
  739.     /* pty */
  740. #ifndef USE_WIN32
  741.     switch(cmd) {
  742.     case CMD_INIT:
  743.         section->option.pty=0;
  744.         break;
  745.     case CMD_EXEC:
  746.         if(strcasecmp(opt, "pty"))
  747.             break;
  748.         if(!strcasecmp(arg, "yes"))
  749.             section->option.pty=1;
  750.         else if(!strcasecmp(arg, "no"))
  751.             section->option.pty=0;
  752.         else
  753.             return "argument should be either 'yes' or 'no'";
  754.         return NULL; /* OK */
  755.     case CMD_DEFAULT:
  756.         break;
  757.     case CMD_HELP:
  758.         log_raw("%-15s = yes|no allocate pseudo terminal for 'exec' option",
  759.             "pty");
  760.         break;
  761.     }
  762. #endif
  763.  
  764.     /* TIMEOUTbusy */
  765.     switch(cmd) {
  766.     case CMD_INIT:
  767.         section->timeout_busy=300; /* 5 minutes */
  768.         break;
  769.     case CMD_EXEC:
  770.         if(strcasecmp(opt, "TIMEOUTbusy"))
  771.             break;
  772.         if(atoi(arg)>0)
  773.             section->timeout_busy=atoi(arg);
  774.         else
  775.             return "Illegal busy timeout";
  776.         return NULL; /* OK */
  777.     case CMD_DEFAULT:
  778.         log_raw("%-15s = %d seconds", "TIMEOUTbusy", section->timeout_busy);
  779.         break;
  780.     case CMD_HELP:
  781.         log_raw("%-15s = seconds to wait for expected data", "TIMEOUTbusy");
  782.         break;
  783.     }
  784.  
  785.     /* TIMEOUTclose */
  786.     switch(cmd) {
  787.     case CMD_INIT:
  788.         section->timeout_close=60; /* 1 minute */
  789.         break;
  790.     case CMD_EXEC:
  791.         if(strcasecmp(opt, "TIMEOUTclose"))
  792.             break;
  793.         if(atoi(arg)>0 || !strcmp(arg, "0"))
  794.             section->timeout_close=atoi(arg);
  795.         else
  796.             return "Illegal close timeout";
  797.         return NULL; /* OK */
  798.     case CMD_DEFAULT:
  799.         log_raw("%-15s = %d seconds", "TIMEOUTclose", section->timeout_close);
  800.         break;
  801.     case CMD_HELP:
  802.         log_raw("%-15s = seconds to wait for close_notify"
  803.             " (set to 0 for buggy MSIE)", "TIMEOUTclose");
  804.         break;
  805.     }
  806.  
  807.     /* TIMEOUTidle */
  808.     switch(cmd) {
  809.     case CMD_INIT:
  810.         section->timeout_idle=43200; /* 12 hours */
  811.         break;
  812.     case CMD_EXEC:
  813.         if(strcasecmp(opt, "TIMEOUTidle"))
  814.             break;
  815.         if(atoi(arg)>0)
  816.             section->timeout_idle=atoi(arg);
  817.         else
  818.             return "Illegal idle timeout";
  819.         return NULL; /* OK */
  820.     case CMD_DEFAULT:
  821.         log_raw("%-15s = %d seconds", "TIMEOUTidle", section->timeout_idle);
  822.         break;
  823.     case CMD_HELP:
  824.         log_raw("%-15s = seconds to keep idle connection", "TIMEOUTidle");
  825.         break;
  826.     }
  827.  
  828.     /* transparent */
  829. #ifndef USE_WIN32
  830.     switch(cmd) {
  831.     case CMD_INIT:
  832.         section->option.transparent=0;
  833.         break;
  834.     case CMD_EXEC:
  835.         if(strcasecmp(opt, "transparent"))
  836.             break;
  837.         if(!strcasecmp(arg, "yes"))
  838.             section->option.transparent=1;
  839.         else if(!strcasecmp(arg, "no"))
  840.             section->option.transparent=0;
  841.         else
  842.             return "argument should be either 'yes' or 'no'";
  843.         return NULL; /* OK */
  844.     case CMD_DEFAULT:
  845.         break;
  846.     case CMD_HELP:
  847.         log_raw("%-15s = yes|no transparent proxy mode",
  848.             "transparent");
  849.         break;
  850.     }
  851. #endif
  852.  
  853.     if(cmd==CMD_EXEC)
  854.         return option_not_found;
  855.     return NULL; /* OK */
  856. }
  857.  
  858. void parse_config(char *name) {
  859. #ifdef CONFDIR
  860.     char *default_config_file=CONFDIR "/stunnel.conf";
  861. #else
  862.     char *default_config_file="stunnel.conf";
  863. #endif
  864.     FILE *fp;
  865.     char line[STRLEN], *arg, *opt, *errstr;
  866.     int line_number, i;
  867.     LOCAL_OPTIONS *section, *new_section;
  868.     
  869.     memset(&options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */
  870.  
  871.     memset(&local_options, 0, sizeof(LOCAL_OPTIONS)); /* reset local options */
  872.     local_options.next=NULL;
  873.     section=&local_options;
  874.  
  875.     global_options(CMD_INIT, NULL, NULL);
  876.     service_options(CMD_INIT, section, NULL, NULL);
  877.     if(!name)
  878.         name=default_config_file;
  879.     if(!strcasecmp(name, "-help")) {
  880.         global_options(CMD_HELP, NULL, NULL);
  881.         service_options(CMD_HELP, section, NULL, NULL);
  882.         exit(1);
  883.     }
  884.     if(!strcasecmp(name, "-version")) {
  885.         log_raw("%s", stunnel_info());
  886.         log_raw(" ");
  887.         global_options(CMD_DEFAULT, NULL, NULL);
  888.         service_options(CMD_DEFAULT, section, NULL, NULL);
  889.         exit(1);
  890.     }
  891.     if(!strcasecmp(name, "-sockets")) {
  892.         print_socket_options();
  893.         exit(1);
  894.     }
  895.     fp=fopen(name, "r");
  896.     if(!fp) {
  897. #ifdef USE_WIN32
  898.         /* Win32 doesn't seem to set errno in fopen() */
  899.         log_raw("Failed to open configuration file %s", name);
  900. #else
  901.         ioerror(name);
  902. #endif
  903.         log_raw(" ");
  904.         log_raw("Syntax:");
  905. #ifdef USE_WIN32
  906.         log_raw("stunnel [filename] | -help | -version | -sockets"
  907.             " | -install | -uninstall");
  908. #else
  909.         log_raw("stunnel [filename] | -help | -version | -sockets");
  910. #endif
  911.         log_raw("    filename    - use specified config file instead of %s",
  912.             default_config_file);
  913.         log_raw("    -help       - get config file help");
  914.         log_raw("    -version    - display version and defaults");
  915.         log_raw("    -sockets    - display default socket options");
  916. #ifdef USE_WIN32
  917.         log_raw("    -install    - install NT service");
  918.         log_raw("    -uninstall  - uninstall NT service");
  919. #endif
  920.         exit(1);
  921.     }
  922.     line_number=0;
  923.     while(fgets(line, STRLEN, fp)) {
  924.         line_number++;
  925.         opt=line;
  926.         while(isspace(*opt))
  927.             opt++; /* remove initial whitespaces */
  928.         for(i=strlen(opt)-1; i>=0 && isspace(opt[i]); i--)
  929.             opt[i]='\0'; /* remove trailing whitespaces */
  930.         if(opt[0]=='\0' || opt[0]=='#') /* empty line or comment */
  931.             continue;
  932.         if(opt[0]=='[' && opt[strlen(opt)-1]==']') { /* new section */
  933.             errstr=section_validate(section);
  934.             if(errstr) {
  935.                 log_raw("file %s line %d: %s", name, line_number, errstr);
  936.                 exit(1);
  937.             }
  938.             opt++;
  939.             opt[strlen(opt)-1]='\0';
  940.             new_section=calloc(1, sizeof(LOCAL_OPTIONS));
  941.             if(!new_section) {
  942.                 log_raw("Fatal memory allocation error");
  943.                 exit(2);
  944.             }
  945.             memcpy(new_section, &local_options, sizeof(LOCAL_OPTIONS));
  946.             new_section->servname=stralloc(opt);
  947.             new_section->next=NULL;
  948.             section->next=new_section;
  949.             section=new_section;
  950.             continue;
  951.         }
  952.         arg=strchr(line, '=');
  953.         if(!arg) {
  954.             log_raw("file %s line %d: No '=' found", name, line_number);
  955.             exit(1);
  956.         }
  957.         *arg++='\0'; /* split into option name and argument value */
  958.         for(i=strlen(opt)-1; i>=0 && isspace(opt[i]); i--)
  959.             opt[i]='\0'; /* remove trailing whitespaces */
  960.         while(isspace(*arg))
  961.             arg++; /* remove initial whitespaces */
  962.         errstr=service_options(CMD_EXEC, section, opt, arg);
  963.         if(section==&local_options && errstr==option_not_found)
  964.             errstr=global_options(CMD_EXEC, opt, arg);
  965.         if(errstr) {
  966.             log_raw("file %s line %d: %s", name, line_number, errstr);
  967.             exit(1);
  968.         }
  969.     }
  970.     errstr=section_validate(section);
  971.     if(errstr) {
  972.         log_raw("file %s line %d: %s", name, line_number, errstr);
  973.         exit(1);
  974.     }
  975.     fclose(fp);
  976.     if(!options.option.client)
  977.         options.option.cert=1; /* Server always needs a certificate */
  978.     if(!options.option.foreground)
  979.         options.option.syslog=1;
  980. }
  981.  
  982. static char *section_validate(LOCAL_OPTIONS *section) {
  983.     if(section==&local_options)
  984.         return NULL; /* No need to validate defaults */
  985. #ifdef USE_WIN32
  986.     if(!section->option.accept || !section->option.remote)
  987. #else
  988.     if((unsigned int)section->option.accept +
  989.             (unsigned int)section->option.program +
  990.             (unsigned int)section->option.remote != 2)
  991. #endif
  992.         return "Each service section must define exactly two endpoints";
  993.     return NULL; /* All tests passed -- continue program execution */
  994. }
  995.  
  996. static char *stralloc(char *str) { /* Allocate static string */
  997.     char *retval;
  998.     
  999.     retval=calloc(strlen(str)+1, 1);
  1000.     if(!retval) {
  1001.         log_raw("Fatal memory allocation error");
  1002.         exit(2);
  1003.     }
  1004.     strcpy(retval, str);
  1005.     return retval;
  1006. }
  1007.  
  1008. #ifndef USE_WIN32
  1009. static char **argalloc(char *str) { /* Allocate 'exec' argumets */
  1010.     int max_arg, i;
  1011.     char *ptr, **retval;
  1012.  
  1013.     max_arg=strlen(str)/2+1;
  1014.     ptr=stralloc(str);
  1015.     retval=calloc(max_arg+1, sizeof(char *));
  1016.     if(!retval) {
  1017.         log_raw("Fatal memory allocation error");
  1018.         exit(2);
  1019.     }
  1020.     i=0;
  1021.     while(*ptr && i<max_arg) {
  1022.         retval[i++]=ptr;
  1023.         while(*ptr && !isspace(*ptr))
  1024.             ptr++;
  1025.         while(*ptr && isspace(*ptr))
  1026.             *ptr++='\0';
  1027.     }
  1028.     retval[i]=NULL;
  1029.     return retval;
  1030. }
  1031. #endif
  1032.  
  1033. int name2nums(char *name, char *default_host, u32 **names, u_short *port) {
  1034.     char tmp[STRLEN], *host_str, *port_str;
  1035.     struct servent *p;
  1036.  
  1037.     safecopy(tmp, name);
  1038.     port_str=strrchr(tmp, ':');
  1039.     if(port_str) {
  1040.         host_str=tmp;
  1041.         *port_str++='\0';
  1042.     } else { /* no ':' - use default host IP */
  1043.         host_str=default_host;
  1044.         port_str=tmp;
  1045.     }
  1046.     *port=htons((u_short)atoi(port_str));
  1047.     if(!*port) { /* Zero is an illegal value for port number */
  1048.         p=getservbyname(port_str, "tcp");
  1049.         if(!p) {
  1050.             log(LOG_ERR, "Invalid port: %s", port_str);
  1051.             return 0;
  1052.         }
  1053.         *port=p->s_port;
  1054.     }
  1055.     return host2nums(host_str, names);
  1056. }
  1057.  
  1058. static int host2nums(char *hostname, u32 **hostlist) {
  1059.         /* get list of host addresses */
  1060.     struct hostent *h;
  1061.     u32 ip;
  1062.     int results, i;
  1063.     char **tab;
  1064.  
  1065.     ip=inet_addr(hostname);
  1066.     if(ip+1) { /* (signed)ip!=-1 */
  1067.         *hostlist=calloc(2, sizeof(u32));
  1068.         if (!*hostlist) {
  1069.             log(LOG_ERR, "Memory allocation error");
  1070.             return 0;
  1071.         }
  1072.         (*hostlist)[0]=ip;
  1073.         (*hostlist)[1]=-1;
  1074.         return 1; /* single result */
  1075.     }
  1076.  
  1077.     /* not dotted decimal - we have to call resolver */
  1078.     if(!(h=gethostbyname(hostname))) { /* get list of addresses */
  1079.         log(LOG_ERR, "Failed to resolve hostname '%s'", hostname);
  1080.         return 0; /* no results */
  1081.     }
  1082.     for(results=0, tab=h->h_addr_list; *tab; tab++)
  1083.         results++;
  1084.     *hostlist=calloc(results+1, sizeof(u32)); /* allocate memory */
  1085.     if (!*hostlist) {
  1086.         log(LOG_ERR, "Memory allocation error");
  1087.         return 0;
  1088.     }
  1089.     for(i=0; i<results; i++) /* copy addresses */
  1090.         (*hostlist)[i]=*(u32 *)(h->h_addr_list[i]);
  1091.     (*hostlist)[results]=-1;
  1092. #ifdef HAVE_ENDHOSTENT
  1093.     endhostent();
  1094. #endif
  1095.     return results;
  1096. }
  1097.  
  1098. /* Parse out the facility/debug level stuff */
  1099.  
  1100. typedef struct {
  1101.     char *name;
  1102.     int value;
  1103. } facilitylevel;
  1104.  
  1105. static int parse_debug_level(char *arg) {
  1106.     char arg_copy[STRLEN];
  1107.     char *string;
  1108.     facilitylevel *fl;
  1109.  
  1110. /* Facilities only make sense on unix */
  1111. #if !defined (USE_WIN32) && !defined (__vms)
  1112.     facilitylevel facilities[] = {
  1113.         {"auth", LOG_AUTH},     {"cron", LOG_CRON},     {"daemon", LOG_DAEMON},
  1114.         {"kern", LOG_KERN},     {"lpr", LOG_LPR},       {"mail", LOG_MAIL},
  1115.         {"news", LOG_NEWS},     {"syslog", LOG_SYSLOG}, {"user", LOG_USER},
  1116.         {"uucp", LOG_UUCP},     {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1},
  1117.         {"local2", LOG_LOCAL2}, {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4},
  1118.         {"local5", LOG_LOCAL5}, {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7},
  1119.  
  1120.         /* Some that are not on all unicies */
  1121. #ifdef LOG_AUTHPRIV
  1122.         {"authpriv", LOG_AUTHPRIV},
  1123. #endif
  1124. #ifdef LOG_FTP
  1125.         {"ftp", LOG_FTP},
  1126. #endif
  1127. #ifdef LOG_NTP
  1128.         {"ntp", LOG_NTP},
  1129. #endif
  1130.         {NULL, 0}
  1131.     };
  1132. #endif /* USE_WIN32, __vms */
  1133.  
  1134.     facilitylevel levels[] = {
  1135.         {"emerg", LOG_EMERG},     {"alert", LOG_ALERT},
  1136.         {"crit", LOG_CRIT},       {"err", LOG_ERR},
  1137.         {"warning", LOG_WARNING}, {"notice", LOG_NOTICE},
  1138.         {"info", LOG_INFO},       {"debug", LOG_DEBUG},
  1139.         {NULL, -1}
  1140.     };
  1141.  
  1142.     safecopy(arg_copy, arg);
  1143.     string = arg_copy;
  1144.  
  1145. /* Facilities only make sense on unix */
  1146. #if !defined (USE_WIN32) && !defined (__vms)
  1147.     if(strchr(string, '.')) { /* We have a facility specified */
  1148.         options.facility=-1;
  1149.         string=strtok(arg_copy, "."); /* break it up */
  1150.  
  1151.         for(fl=facilities; fl->name; fl++) {
  1152.             if(!strcasecmp(fl->name, string)) {
  1153.                 options.facility = fl->value;
  1154.                 break;
  1155.             }
  1156.         }
  1157.         if(options.facility==-1)
  1158.             return 0; /* FAILED */
  1159.         string=strtok(NULL, ".");    /* set to the remainder */
  1160.     }
  1161. #endif /* USE_WIN32, __vms */
  1162.  
  1163.     /* Time to check the syslog level */
  1164.     if(string && strlen(string)==1 && *string>='0' && *string<='7') {
  1165.         options.debug_level=*string-'0';
  1166.         return 1; /* OK */
  1167.     }
  1168.     options.debug_level=8;    /* illegal level */
  1169.     for(fl=levels; fl->name; fl++) {
  1170.         if(!strcasecmp(fl->name, string)) {
  1171.             options.debug_level=fl->value;
  1172.             break;
  1173.         }
  1174.     }
  1175.     if (options.debug_level==8)
  1176.         return 0; /* FAILED */
  1177.     return 1; /* OK */
  1178. }
  1179.  
  1180. /* Parse SSL options stuff */
  1181.  
  1182. static int parse_ssl_option(char *arg) {
  1183.     struct {
  1184.         char *name;
  1185.         long value;
  1186.     } ssl_opts[] = {
  1187.         {"MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG},
  1188.         {"NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG},
  1189.         {"NETSCAPE_REUSE_CIPHER_CHANGE_BUG",
  1190.             SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG},
  1191.         {"SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG},
  1192.         {"MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER},
  1193.         {"MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING},
  1194.         {"SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG},
  1195.         {"TLS_D5_BUG", SSL_OP_TLS_D5_BUG},
  1196.         {"TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG},
  1197.         {"TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG},
  1198. #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
  1199.         {"DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS},
  1200. #endif
  1201.         {"ALL", SSL_OP_ALL},
  1202.         {"SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE},
  1203.         {"EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA},
  1204.         {"NO_SSLv2", SSL_OP_NO_SSLv2},
  1205.         {"NO_SSLv3", SSL_OP_NO_SSLv3},
  1206.         {"NO_TLSv1", SSL_OP_NO_TLSv1},
  1207.         {"PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1},
  1208.         {"PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2},
  1209.         {"NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG},
  1210. #ifdef SSL_OP_NON_EXPORT_FIRST
  1211.         {"NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST},
  1212. #endif
  1213.         {"NETSCAPE_DEMO_CIPHER_CHANGE_BUG",
  1214.             SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG},
  1215.         {NULL, 0}
  1216.     }, *option;
  1217.  
  1218.     for(option=ssl_opts; option->name; option++)
  1219.         if(!strcasecmp(option->name, arg)) {
  1220.             options.ssl_options|=option->value;
  1221.             return 1; /* OK */
  1222.         }
  1223.     return 0; /* FAILED */
  1224. }
  1225.  
  1226. /* Parse out the socket options stuff */
  1227.  
  1228. static int on=1;
  1229.  
  1230. #define DEF_VALS {NULL, NULL, NULL}
  1231. #define DEF_ACCEPT {(void *)&on, NULL, NULL}
  1232.  
  1233. SOCK_OPT sock_opts[] = {
  1234.     {"SO_DEBUG",        SOL_SOCKET,  SO_DEBUG,        TYPE_FLAG,    DEF_VALS},
  1235.     {"SO_DONTROUTE",    SOL_SOCKET,  SO_DONTROUTE,    TYPE_FLAG,    DEF_VALS},
  1236.     {"SO_KEEPALIVE",    SOL_SOCKET,  SO_KEEPALIVE,    TYPE_FLAG,    DEF_VALS},
  1237.     {"SO_LINGER",       SOL_SOCKET,  SO_LINGER,       TYPE_LINGER,  DEF_VALS},
  1238.     {"SO_OOBINLINE",    SOL_SOCKET,  SO_OOBINLINE,    TYPE_FLAG,    DEF_VALS},
  1239.     {"SO_RCVBUF",       SOL_SOCKET,  SO_RCVBUF,       TYPE_INT,     DEF_VALS},
  1240.     {"SO_SNDBUF",       SOL_SOCKET,  SO_SNDBUF,       TYPE_INT,     DEF_VALS},
  1241. #ifdef SO_RCVLOWAT
  1242.     {"SO_RCVLOWAT",     SOL_SOCKET,  SO_RCVLOWAT,     TYPE_INT,     DEF_VALS},
  1243. #endif
  1244. #ifdef SO_SNDLOWAT
  1245.     {"SO_SNDLOWAT",     SOL_SOCKET,  SO_SNDLOWAT,     TYPE_INT,     DEF_VALS},
  1246. #endif
  1247. #ifdef SO_RCVTIMEO
  1248.     {"SO_RCVTIMEO",     SOL_SOCKET,  SO_RCVTIMEO,     TYPE_TIMEVAL, DEF_VALS},
  1249. #endif
  1250. #ifdef SO_SNDTIMEO
  1251.     {"SO_SNDTIMEO",     SOL_SOCKET,  SO_SNDTIMEO,     TYPE_TIMEVAL, DEF_VALS},
  1252. #endif
  1253.     {"SO_REUSEADDR",    SOL_SOCKET,  SO_REUSEADDR,    TYPE_FLAG,    DEF_ACCEPT},
  1254. #ifdef SO_BINDTODEVICE
  1255.     {"SO_BINDTODEVICE", SOL_SOCKET,  SO_BINDTODEVICE, TYPE_STRING,  DEF_VALS},
  1256. #endif
  1257. #ifdef IP_TOS
  1258.     {"IP_TOS",          IPPROTO_IP,  IP_TOS,          TYPE_INT,     DEF_VALS},
  1259. #endif
  1260. #ifdef IP_TTL
  1261.     {"IP_TTL",          IPPROTO_IP,  IP_TTL,          TYPE_INT,     DEF_VALS},
  1262. #endif
  1263. #ifdef IP_MAXSEG
  1264.     {"TCP_MAXSEG",      IPPROTO_TCP, TCP_MAXSEG,      TYPE_INT,     DEF_VALS},
  1265. #endif
  1266.     {"TCP_NODELAY",     IPPROTO_TCP, TCP_NODELAY,     TYPE_FLAG,    DEF_VALS},
  1267.     {NULL,              0,           0,               TYPE_NONE,    DEF_VALS}
  1268. };
  1269.  
  1270. static int print_socket_options(void) {
  1271.     int fd, len;
  1272.     SOCK_OPT *ptr;
  1273.     OPT_UNION val;
  1274.     char line[STRLEN];
  1275.  
  1276.     fd=socket(AF_INET, SOCK_STREAM, 0);
  1277.  
  1278.     log_raw("Socket option defaults:");
  1279.     log_raw("    %-16s%-10s%-10s%-10s%-10s",
  1280.         "Option", "Accept", "Local", "Remote", "OS default");
  1281.     for(ptr=sock_opts; ptr->opt_str; ptr++) {
  1282.         /* display option name */
  1283.         sprintf(line, "    %-16s", ptr->opt_str);
  1284.         /* display stunnel default values */
  1285.         print_option(line, ptr->opt_type, ptr->opt_val[0]);
  1286.         print_option(line, ptr->opt_type, ptr->opt_val[1]);
  1287.         print_option(line, ptr->opt_type, ptr->opt_val[2]);
  1288.         /* display OS default value */
  1289.         len = sizeof(val);
  1290.         if(getsockopt(fd, ptr->opt_level, ptr->opt_name, (void *)&val, &len)) {
  1291.             if(get_last_socket_error()!=ENOPROTOOPT) {
  1292.                 log_raw("%s", line); /* dump the name and assigned values */
  1293.                 sockerror("getsockopt");
  1294.                 return 0; /* FAILED */
  1295.             }
  1296.             safeconcat(line, "    --    "); /* write-only value */
  1297.         } else
  1298.             print_option(line, ptr->opt_type, &val);
  1299.         log_raw("%s", line);
  1300.     }
  1301.     return 1; /* OK */
  1302. }
  1303.  
  1304. static void print_option(char *line, int type, OPT_UNION *val) {
  1305.     char text[STRLEN];
  1306.  
  1307.     if(!val) {
  1308.         safecopy(text, "    --    ");
  1309.     } else {
  1310.         switch(type) {
  1311.         case TYPE_FLAG:
  1312.         case TYPE_INT:
  1313.             sprintf(text, "%10d", val->i_val);
  1314.             break;
  1315.         case TYPE_LINGER:
  1316.             sprintf(text, "%d:%-8d",
  1317.                 val->linger_val.l_onoff, val->linger_val.l_linger);
  1318.             break;
  1319.         case TYPE_TIMEVAL:
  1320.             sprintf(text, "%6d:%-3d",
  1321.                 (int)val->timeval_val.tv_sec, (int)val->timeval_val.tv_usec);
  1322.             break;
  1323.         case TYPE_STRING:
  1324.             sprintf(text, "%10s", val->c_val);
  1325.             break;
  1326.         default:
  1327.             safecopy(text, "  Ooops?  "); /* Internal error? */
  1328.         }
  1329.     }
  1330.     safeconcat(line, text);
  1331. }
  1332.  
  1333. static int parse_socket_option(char *arg) {
  1334.     int socket_type; /* 0-accept, 1-local, 2-remote */
  1335.     char *opt_val_str, *opt_val2_str;
  1336.     SOCK_OPT *ptr;
  1337.  
  1338.     if(arg[1]!=':')
  1339.         return 0; /* FAILED */
  1340.     switch(arg[0]) {
  1341.     case 'a':
  1342.         socket_type=0; break;
  1343.     case 'l':
  1344.         socket_type=1; break;
  1345.     case 'r':
  1346.         socket_type=2; break;
  1347.     default:
  1348.         return 0; /* FAILED */
  1349.     }
  1350.     arg+=2;
  1351.     opt_val_str=strchr(arg, '=');
  1352.     if(!opt_val_str) /* No '='? */
  1353.         return 0; /* FAILED */
  1354.     *opt_val_str++='\0';
  1355.     ptr=sock_opts;
  1356.     for(;;) {
  1357.         if(!ptr->opt_str)
  1358.             return 0; /* FAILED */
  1359.         if(!strcmp(arg, ptr->opt_str))
  1360.             break; /* option name found */
  1361.         ptr++;
  1362.     }
  1363.     ptr->opt_val[socket_type]=calloc(1, sizeof(OPT_UNION));
  1364.     switch(ptr->opt_type) {
  1365.     case TYPE_FLAG:
  1366.     case TYPE_INT:
  1367.         ptr->opt_val[socket_type]->i_val=atoi(opt_val_str);
  1368.         return 1; /* OK */
  1369.     case TYPE_LINGER:
  1370.         opt_val2_str=strchr(opt_val_str, ':');
  1371.         if(opt_val2_str) {
  1372.             *opt_val2_str++='\0';
  1373.             ptr->opt_val[socket_type]->linger_val.l_linger=atoi(opt_val2_str);
  1374.         } else {
  1375.             ptr->opt_val[socket_type]->linger_val.l_linger=0;
  1376.         }
  1377.         ptr->opt_val[socket_type]->linger_val.l_onoff=atoi(opt_val_str);
  1378.         return 1; /* OK */
  1379.     case TYPE_TIMEVAL:
  1380.         opt_val2_str=strchr(opt_val_str, ':');
  1381.         if(opt_val2_str) {
  1382.             *opt_val2_str++='\0';
  1383.             ptr->opt_val[socket_type]->timeval_val.tv_usec=atoi(opt_val2_str);
  1384.         } else {
  1385.             ptr->opt_val[socket_type]->timeval_val.tv_usec=0;
  1386.         }
  1387.         ptr->opt_val[socket_type]->timeval_val.tv_sec=atoi(opt_val_str);
  1388.         return 1; /* OK */
  1389.     case TYPE_STRING:
  1390.         if(strlen(opt_val_str)+1>sizeof(OPT_UNION))
  1391.             return 0; /* FAILED */
  1392.         strcpy(ptr->opt_val[socket_type]->c_val, opt_val_str);
  1393.         return 1; /* OK */
  1394.     default:
  1395.         ; /* ANSI C compiler needs it */
  1396.     }
  1397.     return 0; /* FAILED */
  1398. }
  1399.  
  1400. /* End of options.c */
  1401.